# This file is part of Cantera. See License.txt in the top-level directory or
# at https://cantera.org/license.txt for license and copyright information.

from collections.abc import Callable, Iterable, Sequence
from typing import (
    Any,
    ClassVar,
    Literal,
    overload,
)

from graphviz import Digraph
from typing_extensions import Never, override

from ._types import Array, ArrayLike, LogLevel
from .composite import Solution
from .func1 import _Func1Like
from .jacobians import SystemJacobian
from .kinetics import Kinetics, _DerivativeSettings
from .solutionbase import _SolutionBase
from .thermo import ThermoPhase

class ReactorBase:
    reactor_type: ClassVar[str]
    node_attr: dict[str, str] | None
    def __init__(
        self,
        contents: _SolutionBase | None = None,
        *args: Any,
        clone: bool | None = None,
        name: str = "(none)",
        volume: float | None = None,
        node_attr: dict[str, str] | None = None,
    ) -> None: ...
    @property
    def type(self) -> str: ...
    @property
    def name(self) -> str: ...
    @name.setter
    def name(self, name: str) -> None: ...
    def syncState(self) -> None: ...
    @property
    def phase(self) -> Solution: ...
    @property
    def volume(self) -> float: ...
    @volume.setter
    def volume(self, volume: float) -> None: ...
    @property
    def T(self) -> float: ...
    @property
    def density(self) -> float: ...
    @property
    def mass(self) -> float: ...
    @property
    def Y(self) -> Array: ...
    def add_sensitivity_reaction(self, m: int) -> None: ...
    @property
    def inlets(self) -> list[FlowDevice]: ...
    @property
    def outlets(self) -> list[FlowDevice]: ...
    @property
    def walls(self) -> list[Wall]: ...
    @property
    def surfaces(self) -> list[ReactorSurface]: ...
    def _add_inlet(self, inlet: FlowDevice) -> None: ...
    def _add_outlet(self, outlet: FlowDevice) -> None: ...
    def _add_wall(self, wall: Wall) -> None: ...
    def draw(
        self,
        graph: Digraph | None = None,
        *,
        graph_attr: dict[str, str] | None = None,
        node_attr: dict[str, str] | None = None,
        print_state: bool = False,
        species: Literal["X", "Y"] | bool | Iterable[str] | None = None,
        species_units: Literal["percent", "ppm"] = "percent",
    ) -> Digraph: ...
    @override
    def __reduce__(self) -> Never: ...
    def __copy__(self) -> Never: ...

class Reactor(ReactorBase):
    group_name: str
    def __init__(
        self,
        contents: Solution,
        *,
        name: str = "(none)",
        energy: Literal["on", "off"] = "on",
        group_name: str = "",
        **kwargs: Any,
    ) -> None: ...
    @property
    def chemistry_enabled(self) -> bool: ...
    @chemistry_enabled.setter
    def chemistry_enabled(self, value: bool) -> None: ...
    @property
    def energy_enabled(self) -> bool: ...
    @energy_enabled.setter
    def energy_enabled(self, value: bool) -> None: ...
    def add_sensitivity_species_enthalpy(self, k: int) -> None: ...
    def component_index(self, name: str) -> int: ...
    def component_name(self, i: int) -> str: ...
    @property
    def n_vars(self) -> int: ...
    def get_state(self) -> Array: ...
    @property
    def jacobian(self) -> Array: ...
    @property
    def finite_difference_jacobian(self) -> Array: ...
    def set_advance_limit(self, name: str, limit: float | None) -> None: ...

class MoleReactor(Reactor): ...
class Reservoir(ReactorBase): ...
class ConstPressureReactor(Reactor): ...
class ConstPressureMoleReactor(Reactor): ...
class IdealGasReactor(Reactor): ...
class IdealGasMoleReactor(Reactor): ...
class IdealGasConstPressureReactor(Reactor): ...
class IdealGasConstPressureMoleReactor(Reactor): ...

class FlowReactor(Reactor):
    @property
    def mass_flow_rate(self) -> Never: ...
    @mass_flow_rate.setter
    def mass_flow_rate(self, value: float) -> None: ...
    @property
    def area(self) -> float: ...
    @area.setter
    def area(self, area: float) -> None: ...
    @property
    def inlet_surface_atol(self) -> float: ...
    @inlet_surface_atol.setter
    def inlet_surface_atol(self, atol: float) -> None: ...
    @property
    def inlet_surface_rtol(self) -> float: ...
    @inlet_surface_rtol.setter
    def inlet_surface_rtol(self, rtol: float) -> None: ...
    @property
    def inlet_surface_max_steps(self) -> int: ...
    @inlet_surface_max_steps.setter
    def inlet_surface_max_steps(self, nsteps: int) -> None: ...
    @property
    def inlet_surface_max_error_failures(self) -> int: ...
    @inlet_surface_max_error_failures.setter
    def inlet_surface_max_error_failures(self, nsteps: int) -> None: ...
    @property
    def surface_area_to_volume_ratio(self) -> float: ...
    @surface_area_to_volume_ratio.setter
    def surface_area_to_volume_ratio(self, sa_to_vol: float) -> None: ...
    @property
    def speed(self) -> float: ...

class ExtensibleReactor(Reactor):
    delegatable_methods: dict[str, tuple[str, str]]
    def __init__(self, *args: Any, **kwargs: Any) -> None: ...
    @property
    @override
    def n_vars(self) -> int: ...
    @n_vars.setter
    def n_vars(self, n: int) -> None: ...
    @property
    def expansion_rate(self) -> float: ...
    @expansion_rate.setter
    def expansion_rate(self, vdot: float) -> None: ...
    @property
    def heat_rate(self) -> float: ...
    @heat_rate.setter
    def heat_rate(self, qdot: float) -> None: ...
    def restore_thermo_state(self) -> None: ...
    def restore_surface_state(self, n: int) -> None: ...

class ExtensibleIdealGasReactor(ExtensibleReactor): ...
class ExtensibleConstPressureReactor(ExtensibleReactor): ...
class ExtensibleIdealGasConstPressureReactor(ExtensibleReactor): ...
class ExtensibleMoleReactor(ExtensibleReactor): ...
class ExtensibleIdealGasMoleReactor(ExtensibleReactor): ...
class ExtensibleConstPressureMoleReactor(ExtensibleReactor): ...
class ExtensibleIdealGasConstPressureMoleReactor(ExtensibleReactor): ...

class ReactorSurface:
    reactor_type: ClassVar[str]
    def __init__(
        self,
        contents: _SolutionBase | None = None,
        r: Reactor | None = None,
        *,
        clone: bool | None = None,
        name: str = "(none)",
        A: float | None = None,
        node_attr: dict[str, str] | None = None,
    ) -> None: ...
    @property
    def area(self) -> float: ...
    @area.setter
    def area(self, A: float) -> None: ...
    @property
    def phase(self) -> Solution: ...
    @property
    def coverages(self) -> Array: ...
    @coverages.setter
    def coverages(self, coverages: Array) -> None: ...
    @property
    def reactor(self) -> Reactor: ...
    @property
    def reactors(self) -> list[Reactor]: ...
    def draw(
        self,
        graph: Digraph | None = None,
        *,
        graph_attr: dict[str, str] | None = None,
        node_attr: dict[str, str] | None = None,
        surface_edge_attr: dict[str, str] | None = None,
        print_state: bool = False,
        species: Literal["X", "Y"] | bool | Iterable[str] | None = None,
        species_units: Literal["percent", "ppm"] = "percent",
    ) -> Digraph: ...

class ConnectorNode:
    node_type: ClassVar[str]
    edge_attr: dict[str, str]
    def __init__(
        self,
        left: ReactorBase | None = None,
        right: ReactorBase | None = None,
        upstream: ReactorBase | None = None,
        downstream: ReactorBase | None = None,
        name: str = "(none)",
        **kwargs: Any,
    ) -> None: ...
    @property
    def type(self) -> str: ...
    @property
    def name(self) -> str: ...
    @name.setter
    def name(self, name: str) -> None: ...
    @override
    def __reduce__(self) -> Never: ...
    def __copy__(self) -> Never: ...

class WallBase(ConnectorNode):
    def __init__(
        self,
        left: ReactorBase,
        right: ReactorBase,
        *,
        name: str = "(none)",
        A: float | None = None,
        K: float | None = None,
        U: float | None = None,
        Q: Callable[[float], float] | None = None,
        velocity: Callable[[float], float] | None = None,
        edge_attr: dict[str, str] | None = None,
    ) -> None: ...
    @property
    def area(self) -> float: ...
    @area.setter
    def area(self, value: float) -> None: ...
    @property
    def left_reactor(self) -> ReactorBase: ...
    @property
    def right_reactor(self) -> ReactorBase: ...
    @property
    def expansion_rate(self) -> float: ...
    @property
    def heat_rate(self) -> float: ...
    def draw(
        self,
        graph: Digraph | None = None,
        *,
        graph_attr: dict[str, str] | None = None,
        node_attr: dict[str, str] | None = None,
        edge_attr: dict[str, str] | None = None,
        moving_wall_edge_attr: dict[str, str] | None = None,
        show_wall_velocity: bool = True,
    ) -> Digraph: ...

class Wall(WallBase):
    @property
    def expansion_rate_coeff(self) -> float: ...
    @expansion_rate_coeff.setter
    def expansion_rate_coeff(self, val: float) -> None: ...
    @property
    def heat_transfer_coeff(self) -> float: ...
    @heat_transfer_coeff.setter
    def heat_transfer_coeff(self, value: float) -> None: ...
    @property
    def emissivity(self) -> float: ...
    @emissivity.setter
    def emissivity(self, value: float) -> None: ...
    @property
    def velocity(self) -> float: ...
    @velocity.setter
    def velocity(self, val: _Func1Like) -> None: ...
    @property
    def heat_flux(self) -> float: ...
    @heat_flux.setter
    def heat_flux(self, val: _Func1Like) -> None: ...

class FlowDevice(ConnectorNode):
    def __init__(
        self,
        upstream: ReactorBase,
        downstream: ReactorBase,
        *,
        name: str = "(none)",
        edge_attr: dict[str, str] | None = None,
    ) -> None: ...
    @property
    def upstream(self) -> ReactorBase: ...
    @property
    def downstream(self) -> ReactorBase: ...
    @property
    def mass_flow_rate(self) -> float: ...
    @property
    def pressure_function(self) -> float: ...
    @pressure_function.setter
    def pressure_function(self, val: _Func1Like) -> None: ...
    @property
    def time_function(self) -> float: ...
    @time_function.setter
    def time_function(self, val: _Func1Like) -> None: ...
    @property
    def device_coefficient(self) -> float: ...
    @device_coefficient.setter
    def device_coefficient(self, val: float) -> None: ...
    def draw(
        self,
        graph: Digraph | None = None,
        *,
        graph_attr: dict[str, str] | None = None,
        node_attr: dict[str, str] | None = None,
        edge_attr: dict[str, str] | None = None,
    ) -> Digraph: ...

class MassFlowController(FlowDevice):
    node_type: ClassVar[str]
    def __init__(
        self,
        upstream: ReactorBase,
        downstream: ReactorBase,
        *,
        name: str = "(none)",
        mdot: _Func1Like = 1.0,
        edge_attr: dict[str, str] | None = None,
    ) -> None: ...
    @property
    def mass_flow_coeff(self) -> float: ...
    @mass_flow_coeff.setter
    def mass_flow_coeff(self, value: float) -> None: ...
    @property
    @override
    def mass_flow_rate(self) -> float: ...
    @mass_flow_rate.setter
    def mass_flow_rate(self, m: _Func1Like) -> None: ...

class Valve(FlowDevice):
    node_type: ClassVar[str]
    def __init__(
        self,
        upstream: ReactorBase,
        downstream: ReactorBase,
        *,
        name: str = "(none)",
        K: _Func1Like = 1.0,
        edge_attr: dict[str, str] | None = None,
    ) -> None: ...
    @property
    def valve_coeff(self) -> float: ...
    @valve_coeff.setter
    def valve_coeff(self, value: float) -> None: ...

class PressureController(FlowDevice):
    node_type: ClassVar[str]
    def __init__(
        self,
        upstream: ReactorBase,
        downstream: ReactorBase,
        *,
        name: str = "(none)",
        primary: FlowDevice | None = None,
        K: _Func1Like = 1.0,
        edge_attr: dict[str, str] | None = None,
    ) -> None: ...
    @property
    def pressure_coeff(self) -> float: ...
    @pressure_coeff.setter
    def pressure_coeff(self, value: float) -> None: ...
    @property
    def primary(self) -> Never: ...
    @primary.setter
    def primary(self, d: FlowDevice) -> None: ...

class ReactorNet:
    def __init__(self, reactors: Sequence[Reactor] = ()) -> None: ...
    def advance(self, t: float, apply_limit: bool = True) -> float: ...
    def step(self) -> float: ...
    def solve_steady(self, loglevel: LogLevel = 0) -> None: ...
    def steady_jacobian(self, rdt: float = 0.0) -> Array: ...
    def initialize(self) -> None: ...
    def reinitialize(self) -> None: ...
    @property
    def reactors(self) -> list[Reactor]: ...
    @property
    def time(self) -> float: ...
    @property
    def distance(self) -> float: ...
    @property
    def initial_time(self) -> float: ...
    @initial_time.setter
    def initial_time(self, t: float) -> None: ...
    @property
    def max_time_step(self) -> float: ...
    @max_time_step.setter
    def max_time_step(self, t: float) -> None: ...
    @property
    def max_err_test_fails(self) -> Never: ...
    @max_err_test_fails.setter
    def max_err_test_fails(self, n: int) -> None: ...
    @property
    def max_nonlinear_iterations(self) -> int: ...
    @max_nonlinear_iterations.setter
    def max_nonlinear_iterations(self, n: int) -> None: ...
    @property
    def max_nonlinear_convergence_failures(self) -> int: ...
    @max_nonlinear_convergence_failures.setter
    def max_nonlinear_convergence_failures(self, n: int) -> None: ...
    @property
    def include_algebraic_in_error_test(self) -> bool: ...
    @include_algebraic_in_error_test.setter
    def include_algebraic_in_error_test(self, yesno: bool) -> None: ...
    @property
    def max_order(self) -> Literal[1, 2, 3, 4, 5]: ...
    @max_order.setter
    def max_order(self, n: Literal[1, 2, 3, 4, 5]) -> None: ...
    @property
    def max_steps(self) -> int: ...
    @max_steps.setter
    def max_steps(self, nsteps: int) -> None: ...
    @property
    def rtol(self) -> float: ...
    @rtol.setter
    def rtol(self, tol: float) -> None: ...
    @property
    def atol(self) -> float: ...
    @atol.setter
    def atol(self, tol: float) -> None: ...
    @property
    def rtol_sensitivity(self) -> float: ...
    @rtol_sensitivity.setter
    def rtol_sensitivity(self, tol: float) -> None: ...
    @property
    def atol_sensitivity(self) -> float: ...
    @atol_sensitivity.setter
    def atol_sensitivity(self, tol: float) -> None: ...
    @property
    def verbose(self) -> bool: ...
    @verbose.setter
    def verbose(self, v: bool) -> None: ...
    def global_component_index(self, name: str, reactor: int) -> int: ...
    def component_name(self, i: int) -> str: ...
    def sensitivity(self, component: int | str, p: int, r: int = 0) -> float: ...
    def sensitivities(self) -> Array: ...
    def sensitivity_parameter_name(self, p: int) -> str: ...
    @property
    def n_sensitivity_params(self) -> int: ...
    @property
    def n_vars(self) -> int: ...
    def get_state(self) -> Array: ...
    def get_derivative(self, k: int) -> Array: ...
    @property
    def advance_limits(self) -> Array: ...
    @advance_limits.setter
    def advance_limits(self, limits: ArrayLike | None) -> None: ...
    @overload
    def advance_to_steady_state(
        self,
        max_steps: int,
        residual_threshold: float,
        atol: float,
        return_residuals: Literal[False] = False,
    ) -> None: ...
    @overload
    def advance_to_steady_state(
        self,
        max_steps: int,
        residual_threshold: float,
        atol: float,
        return_residuals: Literal[True],
    ) -> Array: ...
    @overload
    def advance_to_steady_state(
        self,
        max_steps: int = 10000,
        residual_threshold: float = 0.0,
        atol: float = 0.0,
        return_residuals: bool = False,
    ) -> Array | None: ...
    @override
    def __reduce__(self) -> Never: ...
    def __copy__(self) -> Never: ...
    @property
    def preconditioner(self) -> SystemJacobian: ...
    @preconditioner.setter
    def preconditioner(self, precon: SystemJacobian) -> None: ...
    @property
    def linear_solver_type(self) -> Literal["DENSE", "GMRES", "BAND", "DIAG"]: ...
    @linear_solver_type.setter
    def linear_solver_type(
        self, linear_solver_type: Literal["DENSE", "GMRES", "BAND", "DIAG"]
    ) -> None: ...
    @property
    def solver_stats(self) -> dict[str, int]: ...
    @property
    def derivative_settings(self) -> Never: ...
    @derivative_settings.setter
    def derivative_settings(self, value: _DerivativeSettings) -> None: ...
    def draw(
        self,
        *,
        graph_attr: dict[str, str] | None = None,
        node_attr: dict[str, str] | None = None,
        edge_attr: dict[str, str] | None = None,
        heat_flow_attr: dict[str, str] | None = None,
        mass_flow_attr: dict[str, str] | None = None,
        moving_wall_edge_attr: dict[str, str] | None = None,
        surface_edge_attr: dict[str, str] | None = None,
        show_wall_velocity: bool = True,
        print_state: bool = False,
        species: Literal["X", "Y"] | bool | Iterable[str] | None = None,
        species_units: Literal["percent", "ppm"] = "percent",
    ) -> Digraph: ...
